//
//  DictionaryExtension.swift
//  SwiftUI
//
//  Created by lvfeijun on 2021/12/28.
//  Copyright © 2021 lvfeijun. All rights reserved.
//

import Foundation
import UIKit

extension Dictionary {
    
    /// EZSE: 从字典中返回随机键值对的值
    public func random() -> Value? {
        return Array(values).random()
    }
    
    public func union(_ dictionaries: Dictionary...) -> Dictionary {
        var result = self
        dictionaries.forEach{ (dictionary) -> Void in
            dictionary.forEach{ (arg) -> Void in
                
                let (key, value) = arg
                result[key] = value
            }
        }
        return result
    }
    
    /// EZSE: 检查字典中是否存在键。
    public func has(_ key: Key) -> Bool {
        return index(forKey: key) != nil
    }
    
    /// EZSE：使用运行生成的值创建一个数组
    /// each[key: value] self 通过mapFunction。
    public func toArray<V>(_ map: (Key, Value) -> V) -> [V] {
        return self.map(map)
    }
    
    /// EZSE: 使用与 self 相同的键和运行生成的值创建一个字典
    /// 每个[key: value] self 通过mapFunction。
    public func mapValues<V>(_ map: (Key, Value) -> V) -> [Key: V] {
        var mapped: [Key: V] = [:]
        forEach {
            mapped[$0] = map($0, $1)
        }
        return mapped
    }
    
    /// EZSE: 使用与 self 相同的键和运行生成的值创建一个字典
    /// 每个 [key: value] self 通过 mapFunction 丢弃 nil 返回值。
    public func mapFilterValues<V>(_ map: (Key, Value) -> V?) -> [Key: V] {
        var mapped: [Key: V] = [:]
        forEach {
            if let value = map($0, $1) {
                mapped[$0] = value
            }
        }
        return mapped
    }
    
    /// EZSE：使用运行生成的键和值创建字典
    /// 每个 [key: value] self 通过 mapFunction 丢弃 nil 返回值。
    public func mapFilter<K, V>(_ map: (Key, Value) -> (K, V)?) -> [K: V] {
        var mapped: [K: V] = [:]
        forEach {
            if let value = map($0, $1) {
                mapped[value.0] = value.1
            }
        }
        return mapped
    }
    
    /// EZSE：使用运行生成的键和值创建字典
    /// 每个[key: value] self 通过mapFunction。
    public func map<K, V>(_  map: (Key, Value) -> (K, V)) -> [K: V] {
        var mapped: [K: V] = [:]
        forEach {
            let (_key, _value) = map($0, $1)
            mapped[_key] = _value
        }
        return mapped
    }
    
    /// EZSE：构造一个字典，其中包含来自 self 的每个 [key: value] 对
    /// testFunction 评估为真。
    public func filter(_ test: (Key, Value) -> Bool) -> Dictionary {
        var result = Dictionary()
        for (key, value) in self {
            if test(key, value) {
                result[key] = value
            }
        }
        return result
    }
    
    /// EZSE：检查测试是否对 self 中的所有元素评估为真。
    public func testAll(_ test: (Key, Value) -> (Bool)) -> Bool {
        return !contains{ !test($0, $1) }
    }
    
    /// EZSE: 将 JSON 字符串反序列化为字典
    public static func constructFromJSON (json: String) -> Dictionary? {
        if let data = (try? JSONSerialization.jsonObject(with: json.data(using: String.Encoding.utf8, allowLossyConversion: true)!, options: JSONSerialization.ReadingOptions.mutableLeaves)) as? Dictionary {
            return data
        } else {
            return nil
        }
    }
    
    /// EZSE: 将字典序列化为 JSON 字符串
    public func fromatJSON() -> String? {
        if let jsonData = try? JSONSerialization.data(withJSONObject: self, options: JSONSerialization.WritingOptions()) {
            let jsonStr = String(data: jsonData, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue))
            return String(jsonStr ?? "" )
        }
        return nil
    }
    
}

extension Dictionary where Value: Equatable {
    /// EZSE: self 和输入字典的差异。
    /// 如果两个字典包含相同的 [key: value] 对，则它们被认为是相等的。
    public func difference(_ dictionaries: [Key: Value]...) -> [Key: Value] {
        var result = self
        for dictionary in dictionaries {
            for (key, value) in dictionary {
                if result.has(key) && result[key] == value {
                    result.removeValue(forKey: key)
                }
            }
        }
        return result
    }
    
    
    
}

/// EZSE: 将第一个字典与第二个字典组合并返回单个字典
public func += <KeyType, ValueType> (left: inout [KeyType: ValueType], right: [KeyType: ValueType]) {
    for (k, v) in right {
        left.updateValue(v, forKey: k)
    }
}
